﻿// (c)2010 David Schwarz (david.schwarz@live.com)
// This file is licensed under GNU GPL v2 license, see more at http://www.gnu.org/licenses/gpl-2.0.html
namespace Z2.Core
{

	#region Using

	using System;
	using Microsoft.Xna.Framework;
	using Microsoft.Xna.Framework.Content;
	using Microsoft.Xna.Framework.Graphics;

	#endregion

	/// <summary>
	/// Efekt "pod vodou" (PixelShader)
	/// </summary>
	public class EffectUnderWater : EffectBase
	{

		#region Const

		private const float REFRACTION_SPEED = 0.02f;

		#endregion

		#region Members

		private ResolveTexture2D m_resolveTex;
		private Effect m_refractionEffect;
		private Texture2D m_underWater;
		private Rectangle m_rect;

		private bool m_disposed;
		private bool m_disposing;

		#endregion

		#region Constructor

		/// <summary>
		/// Konstruktor
		/// </summary>
		/// <param name="content"><see cref="ContentManager"/></param>
		/// <param name="graphics"><see cref="GraphicsDeviceManager"/></param>
		public EffectUnderWater(ContentManager content, GraphicsDeviceManager graphics)
			: base(content, graphics)
		{
			// Inicializace PixelShader efektu
			this.m_refractionEffect = this.Content.Load<Effect>("Graphics/refraction");
			this.m_underWater = this.Content.Load<Texture2D>("Graphics/underwater"); // Inicializace textury
			
			// Inicializace textury, do které se bude kopírovat obsah bufferu
			this.m_resolveTex = new ResolveTexture2D(this.Graphics.GraphicsDevice,
				this.Graphics.GraphicsDevice.PresentationParameters.BackBufferWidth,
				this.Graphics.GraphicsDevice.PresentationParameters.BackBufferHeight, 1,
				this.Graphics.GraphicsDevice.PresentationParameters.BackBufferFormat);

			// Reg. události změny vlastností zařízení
			this.Graphics.PreparingDeviceSettings += new EventHandler<PreparingDeviceSettingsEventArgs>(Graphics_PreparingDeviceSettings);
			this.InitializeRect();
		}

		#endregion

		#region Methods

		/// <summary>
		/// Inicializace rectu celého viewportu
		/// </summary>
		private void InitializeRect()
		{
			Viewport viewport = this.Graphics.GraphicsDevice.Viewport;
			this.m_rect = new Rectangle(0, 0, viewport.Width, viewport.Height);
		}

		/// <summary>
		/// Vrací vektor, který se bohybuje v kruzích (podle celk. času hry)
		/// </summary>
		/// <param name="gameTime"><see cref="GameTime"/></param>
		/// <param name="speed">Rychlost</param>
		/// <returns><see cref="Vector2"/></returns>
		private static Vector2 MoveInCircle(GameTime gameTime, float speed)
		{
			double time = gameTime.TotalGameTime.TotalSeconds * speed;
			return new Vector2(
				(float)Math.Cos(time), 
				(float)Math.Sin(time));
		}

		/// <summary>
		/// Metoda vykreslí refrection effect
		/// </summary>
		/// <param name="batch"><see cref="SpriteBatch"/></param>
		/// <param name="gameTime"><see cref="GameTime"/></param>
		public override void Draw(SpriteBatch batch, GameTime gameTime)
		{
			batch.Begin(SpriteBlendMode.AlphaBlend, SpriteSortMode.Immediate, SaveStateMode.SaveState);

			this.Graphics.GraphicsDevice.Textures[1] = this.m_underWater;
			this.m_refractionEffect.Parameters["DisplacementScroll"].SetValue(EffectUnderWater.MoveInCircle(gameTime, EffectUnderWater.REFRACTION_SPEED));

			this.m_refractionEffect.Begin();
			this.m_refractionEffect.CurrentTechnique.Passes[0].Begin();

			this.Graphics.GraphicsDevice.ResolveBackBuffer(this.m_resolveTex);

			batch.Draw(this.m_resolveTex, this.m_rect, this.m_rect, Color.White);

			batch.End();

			this.m_refractionEffect.CurrentTechnique.Passes[0].End();
			this.m_refractionEffect.End();
		}

		#endregion

		#region Override Methods

		/// <summary>
		/// Uvolnění paměti
		/// </summary>
		public override void Dispose()
		{
			if (this.m_disposed || this.m_disposing)
			{
				return;
			}

			this.m_disposing = true;
			
			this.m_refractionEffect.Dispose();
			this.m_resolveTex.Dispose();
			this.m_underWater.Dispose();

			this.m_disposed = true;
			base.Dispose();
		}

		#endregion

		#region Event Handling

		/// <summary>
		/// Reakce na změny v <see cref="GraphicsDevice"/>
		/// </summary>
		/// <param name="sender"></param>
		/// <param name="e"></param>
		void Graphics_PreparingDeviceSettings(object sender, PreparingDeviceSettingsEventArgs e)
		{
			this.InitializeRect();
		}

		#endregion

	}
}
